#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
protocol_demo.py - 通信协议测试

Author: xiaobo (xiaobocwb@gmail.com)
Version: 1.0.0
Date: 2024-01

Copyright (c) 2024 xiaobo
Licensed under the MIT License
"""

import sys
import time
import os
import threading
import signal
import serial
import argparse
import logging

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from protocol import Protocol

script_dir = os.path.dirname(os.path.abspath(__file__))
test_firmware_path = os.path.join(script_dir, "../test/firmware.txt")


# 消息定义（需要通信双方互相约定一致）
TEST_TOPIC       = 0x01
OTA_INFO_TOPIC   = 0x02
OTA_DATA_TOPIC   = 0x03
OTA_END_TOPIC    = 0x04

# 缓冲区大小
BUFFER_SIZE = 1024

# DTU 测试 OTA 下发
def test_dtu_ota_download(proto, file_path):
    file = open(file_path, "rb")
    file_size = os.path.getsize(file_path)
    file.seek(0, 0)

    logging.info("DTU 发送 OTA 信息")
    if not proto.publish_try(OTA_INFO_TOPIC, file_size.to_bytes(4, "little"), True, 0.2, 3):
        logging.error("DTU 发送 OTA 信息失败")
        return False
    else:
        logging.info("DTU 发送 OTA 信息成功")


    send_size = 0
    while True:
        data = file.read(BUFFER_SIZE)
        if not data:
            break
        if not proto.publish_try(OTA_DATA_TOPIC, data, True, 0.2, 3):
            logging.error("DTU 发送失败")
            return False
        send_size += len(data)
        logging.info(f"DTU 发送进度: {send_size / file_size * 100:.2f}%")
        time.sleep(0.01)


    if not proto.publish_try(OTA_END_TOPIC, b"", True, 0.2, 3):
        logging.error("DTU 发送结束失败")
        return False
    else:
        logging.info("DTU 发送结束成功")

    file.close()
    return True


# 接收线程
def recv_thread_func(proto, serial):
    while True:
        data = serial.read(BUFFER_SIZE)
        if data:
            proto.parse(data)


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='UART Protocol')
    parser.add_argument('port', type=str, help='UART port', default="/dev/ttyVSP1")
    parser.add_argument('baudrate', type=int, help='UART baudrate', default=115200)

    args = parser.parse_args()
    port = args.port
    baudrate = args.baudrate

    # 测试通过传入的设备名判断是 DTU 还是 Turbo
    is_dtu = False
    if "ttyVSP1" in port:
        is_dtu = True
        logging.info("DTU 模式")
    else:
        logging.info("Turbo 模式")


    # 初始化串口和协议
    serial = serial.Serial(port, baudrate, timeout=0.001)
    proto = Protocol(serial.write)

    # 启动接收线程
    thread = threading.Thread(target=recv_thread_func, args=(proto, serial))
    thread.start()


    # 订阅消息
    if is_dtu:
        proto.subscribe(TEST_TOPIC, lambda topic, payload: logging.info(f"DTU 收到测试消息: msgid={topic}, len={len(payload)}, payload={int.from_bytes(payload, 'little')}"))
    else:
        proto.subscribe(OTA_INFO_TOPIC, lambda topic, payload: logging.info(f"Turbo 收到 OTA 信息 msgid={topic}, len={len(payload)}, payload={int.from_bytes(payload, 'little')}"))
        proto.subscribe(OTA_DATA_TOPIC, lambda topic, payload: logging.info(f"Turbo 收到 OTA 数据 msgid={topic}, len={len(payload)}"))
        proto.subscribe(OTA_END_TOPIC, lambda topic, payload: logging.info(f"Turbo 收到 OTA 结束 msgid={topic}, len={len(payload)}"))

    time.sleep(1)   # 等待另一个模拟测试进程启动
    # 测试代码
    if is_dtu:
        if not test_dtu_ota_download(proto, test_firmware_path):
            logging.error("DTU OTA 测试失败")
        else:
            logging.info("DTU OTA 测试成功")
        while True:
            time.sleep(1)
    else:
        logging.info("Turbo 0.1 秒发送一次测试消息")
        counter = 30 
        while counter > 0:
            if proto.publish(TEST_TOPIC, counter.to_bytes(2, "little"), True, 0.2):
                logging.info(f"Turbo 发送测试消息成功: {counter}")
            else:
                logging.error(f"Turbo 发送测试消息失败")
            counter -= 1
            time.sleep(0.01)



